home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / CAD / ACDCHORD.ARJ / ACDCHORD.ASM next >
Assembly Source File  |  1990-07-14  |  26KB  |  1,033 lines

  1.     TITLE    ACDCHORD.COM, an ADI driver to make AutoCAD use chords
  2.             
  3.     PAGE    ,132
  4.  
  5. ;Written by Jon Fleming     6/2/90
  6. ;        144 Nagog Hill Road
  7. ;        Acton, MA 01720
  8.  
  9. ;        BIXname: jfleming
  10.  
  11. ;Released into the public domain.
  12.  
  13. ;To create ACDCHORD.COM:
  14. ;    MASM ACDCHORD;
  15. ;    LINK ACDCHORD;
  16. ;    EXE2BIN ACDCHORD.EXE ACDCHORD.COM
  17.  
  18. ;This version was assembled with Microsoft MASM 5.1.
  19.  
  20. ;If you have DOS 3.3 and do not have the technical reference, you probably
  21. ;don't have EXE2BIN.  There are public domain programs that do the same thing
  22. ;(such as EXE2COM), available on many bulletin board systems.
  23.  
  24.  
  25. ;****************** EQUATES *********************
  26.  
  27. ;general purpose
  28.  
  29. false    equ    0
  30. true    equ    1
  31.  
  32. stdout    equ    1    ;standard output device handle
  33.  
  34.  
  35. tab        equ    9
  36. lf        equ    0ah
  37. form_feed    equ    0ch
  38. cr        equ    0dh
  39. esc_char    equ    1bh
  40. space        equ    20h
  41.  
  42. ;ACDCHORD equates
  43.  
  44. default_interrupt    equ    79h    ;default interrupt for us
  45.                     ; to communicate with
  46.                     ; AutoCAD
  47.  
  48. default_multiplier    equ    24d    ;default multiplier for all
  49.                     ;mouse motions
  50.  
  51. ;AutoCAD codes
  52.  
  53. init_driver_code        equ    1    ;codes for what AutoCAD
  54. terminate_driver_code    equ    2    ; wants
  55. sense_state_code        equ    3
  56.  
  57. interface_level            equ    1    ;identifies driver interface
  58.                     ;  version
  59.  
  60. ;mouse codes
  61.  
  62. mouse_driver_installed    equ    0FFFFh
  63. read_pos_and_buttons    equ    3
  64. read_counters_function    equ    0Bh
  65.  
  66. ;********************** END EQUATES **************
  67.  
  68. stack    segment    stack            ;just so the linker doesn't issue a
  69.                     ; warning.
  70. stack    ends                ;DON'T put anything in this segment!
  71.  
  72. ;collect all the segments in one group so we can turn this into a COM program
  73.     program    group    main_code,resident_data,transient_code,transient_data
  74.     assume cs:program,ds:program,es:program,ss:program
  75.  
  76. main_code    segment
  77.  
  78.  
  79. ;************************** RESIDENT DATA *******************************
  80.  
  81. resident_data    segment    byte        ;this segment will FOLLOW the
  82.                     ; resident code and contains all the
  83.                     ; data that will remain resident
  84.                     ; after terminate and stay resident
  85.                     ;call
  86.  
  87. ; Translate table for a three button mouse, to translate single buttons
  88. ;  and chords into AutoCAD button numbers
  89.  
  90. button_translate_table  db      1       ;right button = button 1
  91.                         db      4       ;left+right buttons = button 4
  92.                         db      0       ;middle button = button 0
  93.                         db      2       ;left+middle buttons = button 2
  94.                         db      3       ;middle+right buttons = button 3
  95.                         db      5       ;left+middle+right buttons = button 5
  96.  
  97. motion_scale_factor    dw    default_multiplier    ;factor by which to
  98.                     ; multiply mouse motions
  99.  
  100. save_button_status    db    0    ;space for saving button status until
  101.                     ; all buttons are released
  102.  
  103. x_coord            dw    0    ;space for saving mouse position
  104. y_coord            dw    0
  105.  
  106. end_resident_data       label   byte    ;used for getting resident size
  107.  
  108. resident_data    ends
  109.  
  110.  
  111. ;************************ TRANSIENT DATA *****************************
  112.  
  113.  
  114. transient_code    segment    byte        ;the transient code will FOLLOW the
  115.                     ; resident data
  116.  
  117.  
  118. transient_data    segment    byte        ;the transient data will FOLLOW the
  119.                     ; transient code
  120.  
  121. installed_message    db    cr,lf,'AutoCAD/Chord mouse'
  122.             db    ' driver installed, using interrupt '
  123. int_num_ascii_1        dw    ?
  124.             db    ' (hexadecimal),',cr,lf,'occupying '
  125.             db    2 dup (space)
  126. end_decimal_ascii_0    db    space
  127.             db    ' (decimal) bytes; mouse motions '
  128.             db    'multiplied by  '
  129. end_decimal_ascii_1    db    space
  130.             db    '.',cr,lf,'$'
  131.  
  132. not_installed_msg    db    cr,lf,'AutoCAD/Chord mouse'
  133.             db    ' driver *NOT* installed '
  134.             db    'on interrupt '
  135. int_num_ascii_3        dw    ?
  136.             db    ' (hexadecimal),',cr,lf
  137.             db    'operation aborted.',cr,lf,'$'
  138.  
  139. already_installed_msg    db    cr,lf,'AutoCAD/Chord mouse driver '
  140.             db    'already installed on interrupt '
  141. int_num_ascii_4        dw    ?
  142.             db    ' (hexadecimal).',cr,lf,'$'
  143.  
  144. new_multiplier_msg    db    'Multiplier set to  '
  145. end_decimal_ascii_2    db    space
  146.             db    '.',cr,lf,'$'
  147.  
  148. cmd_error_message    db    cr,lf,'AutoCAD/Chord mouse driver: '
  149.             db    'cannot decode command line.',cr,lf
  150.             db    'Valid command line items are:',cr,lf,lf
  151.             db    '/Inn        Use interrupt nn (hexadecimal).'
  152.             db    cr,lf
  153.             db    '            (nn MUST be two digits).',cr,lf
  154.             db    '            The default interrupt number is '
  155. int_num_ascii_0        dw    ?
  156.             db    '.',cr,lf,lf
  157.             db    '/Mxx        Multiply all mouse motions by xx '
  158.             db    '(decimal).',cr,lf
  159.             db    '            (xx may be one or more digits).'
  160.             db    cr,lf
  161.             db    '            The default multiplier is  '
  162. end_decimal_ascii_4    db    space
  163.             db    '.',cr,lf,lf,'The /M switch can be used after '
  164.             db    'installation to change the multiplier.'
  165.             db    cr,lf,lf
  166.             db    'If ACDCHORD is already installed using '
  167.             db    'other than the default interrupt',cr,lf
  168.             db    'AND the multiplier is to be changed, the /I'
  169.             db    ' switch MUST be included',cr,lf
  170.             db    'and MUST specify the same interrupt used'
  171.             db    ' when ACDCHORD was installed.',cr,lf,lf,'$'
  172.  
  173. env_error_message    db    cr,lf,'error releasing environment space, '
  174.             db    'aborting.',cr,lf,'$'
  175.  
  176. interrupt_err_message    db    cr,lf,'Interrupt '
  177. int_num_ascii_2        dw    ?
  178.             db    ' (hexadecimal) is in use already, '
  179.             db    'installation aborted.',cr,lf,'$'
  180.  
  181. bad_int_err_message    db    cr,lf,'Error, invalid hexadecimal interrupt'
  182.             db    ' number.',cr,lf,'$'
  183.  
  184. bad_multiplier_err_msg    db    cr,lf,'Error, invalid number following'
  185.             db    ' multiplier switch.',cr,lf,'$'
  186.  
  187. not_enough_room_msg    db    cr,lf,'Not enough memory available to'
  188.             db    'install driver, aborting',cr,lf,'$'
  189.  
  190. our_interrupt        db    default_interrupt
  191.  
  192. multiplier_update    db    false    ;flag for whether we should update
  193.                     ; the multiplier in a resident copy
  194.  
  195. iret_instruction    label    byte
  196.         iret            ;something to compare against to see
  197.                     ; if a byte is an interrupt return
  198. transient_data    ends
  199.  
  200. ;************************* TRANSIENT CODE ********************
  201.  
  202.     assume cs:program,ds:program,es:program,ss:program
  203.  
  204. start_transient_code:
  205.  
  206.     mov    dl,default_interrupt
  207.     call    byte_to_hex_ascii    ;convert default interrupt
  208.     xchg    ah,al            ; (swap to set up for word store)
  209.     mov    int_num_ascii_0,ax    ; to ASCII and store it where
  210.     mov    int_num_ascii_1,ax    ; we may need it later
  211.     mov    int_num_ascii_2,ax
  212.       mov    int_num_ascii_3,ax
  213.     mov    int_num_ascii_4,ax
  214.  
  215.     mov    dx,motion_scale_factor    ;convert the motion scale factor
  216.     mov    di,offset program:end_decimal_ascii_1    ; to ASCII and store
  217.     call    word_to_decimal_ascii            ; it where we may
  218.     mov    di,offset program:end_decimal_ascii_2    ; need it later
  219.     call    word_to_decimal_ascii
  220.     mov    di,offset program:end_decimal_ascii_4
  221.     call    word_to_decimal_ascii
  222.  
  223. figure_out_what_to_do:
  224.     call    scan_cmd_tail        ;see if anything on command tail
  225.     jc    try_to_install        ;reached end of command tail
  226.  
  227.     cmp    al,'I'
  228.     je    user_specified_interrupt
  229.  
  230.     cmp    al,'M'
  231.     je    user_specified_multiplier
  232.  
  233.     mov    al,3            ;undecodable switch exit code
  234.     jmp    error_exit
  235.  
  236. user_specified_interrupt:
  237.     lodsw                     ;get interrupt number
  238.  
  239.     mov    int_num_ascii_1,ax    ;save into messages
  240.     mov    int_num_ascii_2,ax
  241.     mov    int_num_ascii_3,ax
  242.     mov    int_num_ascii_4,ax
  243.     xchg    ah,al            ;set up for conversion
  244.  
  245.     call    hex_ascii_to_byte    ;convert it to binary
  246.     jc    user_specified_interrupt_error
  247.     mov    our_interrupt,al     ;and save it
  248.  
  249.     jmp    figure_out_what_to_do
  250.  
  251. user_specified_interrupt_error:
  252.     mov    dx,offset program:bad_int_err_message
  253.     mov    ah,9
  254.     int    21h
  255.  
  256.     mov    al,1            ;bad interrupt exit code
  257.     jmp    error_exit
  258.  
  259. user_specified_multiplier:
  260.     call    decimal_ascii_to_word    ;convert to binary
  261.  
  262.     cmp    dx,0            ;check that it's OK
  263.     je    user_specified_multiplier_error
  264.  
  265.     mov    motion_scale_factor,dx    ;store in current copy of routine
  266.  
  267.     mov    end_decimal_ascii_1 - 1,space    ;in case the new one is one
  268.     mov    end_decimal_ascii_2 - 1,space    ;digit and the old one was
  269.                         ; two digits
  270.  
  271.     mov    di,offset program:end_decimal_ascii_1    ;store the motion
  272.     call    word_to_decimal_ascii            ; scale factor in
  273.     mov    di,offset program:end_decimal_ascii_2    ; the messages
  274.     call    word_to_decimal_ascii
  275.  
  276.     mov    multiplier_update,true    ;set flag for action later
  277.  
  278.     jmp    figure_out_what_to_do
  279.  
  280. user_specified_multiplier_error:
  281.     mov    dx,offset program:bad_multiplier_err_msg
  282.     mov    ah,9
  283.     int    21h
  284.  
  285.     mov    al,2            ;bad multiplier exit code
  286.     jmp    error_exit
  287.  
  288.  
  289. try_to_install:
  290.     mov    al,our_interrupt
  291.     call    check_interrupt        ;see if the interrupt is free
  292.  
  293.     cmp    al,0
  294.     je    ok_to_install        ;nobody's there already
  295.     cmp    al,1
  296.     je    already_installed    ;we're there already
  297.  
  298.                     ;someone else is there
  299.     mov    dx,offset program:interrupt_err_message
  300.     jmp    short installation_error
  301.  
  302. already_installed:
  303.     mov    dx,offset program:already_installed_msg
  304.     mov    ah,9
  305.     int    21h            ;write installation message
  306.  
  307.     cmp    multiplier_update,false
  308.     je    already_installed_exit
  309.                     ;we need to update the
  310.                     ; multiplier in the resident copy
  311.  
  312.     mov    al,our_interrupt    ;get the location of the resident
  313.     mov    ah,35h                   ; copy
  314.     int    21h
  315.     assume    es:nothing          
  316.  
  317.     mov    ax,motion_scale_factor    ;store the new multiplier in the
  318.     mov    bx,offset program:motion_scale_factor    ; resident copy
  319.     mov    es:[bx],ax
  320.     mov    ax,cs
  321.     mov    es,ax
  322.     assume    es:program
  323.  
  324.     mov    dx,offset program:new_multiplier_msg
  325.     mov    ah,9
  326.     int    21h            ;tell user we changed multiplier
  327.  
  328. already_installed_exit:
  329.     mov    ax,4c00h
  330.     int    21h            ;terminate, return code 0
  331.  
  332. ok_to_install:
  333.     mov    ah,49h
  334.     mov    bx,env_segment
  335.     mov    es,bx
  336.     assume es:nothing
  337.     int    21h            ;release our environment block
  338.  
  339.     mov    ax,cs
  340.     mov    es,ax            ;reestablish ES
  341.     assume es:program
  342.  
  343.     jnc    check_size
  344.  
  345.     mov    dx,offset program:env_error_message
  346.     jmp     short installation_error
  347.  
  348. check_size:
  349.     mov    dx,offset program:resident_data
  350.         add     dx,15
  351.     mov    cl,4
  352.     shr    dx,cl            ;dx = length of resident portion in
  353.                     ; paragraphs
  354.     push    dx            ;save for later
  355.  
  356.     shl    dx,cl            ;convert back to bytes
  357.  
  358.     mov    di,offset program:end_decimal_ascii_0
  359.     call    word_to_decimal_ascii    ;let the user know how much room
  360.                     ; we're using
  361.  
  362.     cmp    dx,sp            ;is there enough room for us?
  363.     jbe    grab_the_interrupt
  364.  
  365.     mov    dx,offset program:not_enough_room_msg
  366.     mov    ah,9
  367.     int    21h
  368.  
  369.     mov    al,4            ;insufficient room exit code
  370.     jmp    short error_exit
  371.  
  372. grab_the_interrupt:
  373.     mov    ah,25h
  374.     mov    al,our_interrupt
  375.     mov    dx,offset program:interrupt_handler
  376.     int    21h            ;grab the interrupt
  377.  
  378.     mov    dx,offset program:installed_message
  379.     mov    ah,9
  380.     int    21h            ;write installation message
  381.  
  382.     pop    dx            ;length of resident portion, paras
  383.     mov    ax,3100h
  384.     int    21h            ;terminate and stay resident
  385.  
  386. installation_error:
  387.     mov    ah,9
  388.     int    21h            ;describe error
  389.  
  390.     mov    dx,offset program:not_installed_msg
  391.     mov    ah,9
  392.     int    21h            ;tell user we didn't install
  393.  
  394.     mov    al,5            ;other installation error code
  395.  
  396. error_exit:
  397.     push    ax            ;save error code
  398.  
  399.     mov    dx,offset program:cmd_error_message
  400.     mov    ah,9
  401.     int    21h            ;show help
  402.  
  403.     pop    ax
  404.  
  405.     mov    ah,4ch
  406.     int    21h            ;terminate with return code nonzero
  407.  
  408. ;*************************** TRANSIENT SUPPORT ROUTINES **************
  409.  
  410. word_to_decimal_ascii    proc    near
  411. ;convert a 16 bit binary number in DX to its decimal ASCII equivalent, and
  412. ;store the result in the area pointed to by ES:DI.  STORING IS BACKWARDS so
  413. ;ES:DI should point to the _END_ of the area where storage is desired.
  414.  
  415.     push    ax
  416.     push    cx
  417.     push    dx
  418.     pushf
  419.  
  420.     std                ;reverse moves
  421.  
  422.     mov    cx,10            ;divisor
  423.  
  424. word_to_decimal_ascii_loop:
  425.     mov    ax,dx            ;current binary value
  426.     xor    dx,dx
  427.  
  428.     div    cx
  429.  
  430.     xchg    ax,dx            ;quotient to AX
  431.     add    al,30h            ;next digit to ASCII
  432.  
  433.     stosb                ;store it
  434.  
  435.     or    dx,dx            ;all done?
  436.     jnz    word_to_decimal_ascii_loop
  437.  
  438.     popf
  439.     pop    dx
  440.     pop    cx
  441.     pop    ax
  442.  
  443.     ret
  444.  
  445. word_to_decimal_ascii    endp
  446.  
  447. byte_to_hex_ascii    proc    near
  448. ;converts an 8 bit number in DL to an ASCII hex representation in AX
  449.  
  450.     push    cx
  451.  
  452.     mov    cx,4
  453.     xor    ah,ah
  454.  
  455.     mov    al,dl
  456.     shr    ax,cl            ;isolate upper four bits
  457.  
  458.     lahf                ;make sure auxiliary carry wasn't set
  459.     and    ah,11101110b        ; by "shr" op, which happens on some
  460.     sahf                ; CPUs in the iapx family
  461.  
  462.     daa                ;add 6 if 0Ah through 0Fh
  463.     add    al,0f0h            ;and set carry if 0Ah through 0Fh
  464.     adc    al,40h            ;like magic, it's ASCII!
  465.  
  466.     xchg    ah,al            ;save MSD in AH
  467.  
  468.     mov    al,dl
  469.     and    al,0fh            ;get lower four bits
  470.     daa                ;add 6 if 0Ah through 0Fh
  471.     add    al,0f0h            ;and set carry if 0Ah through 0Fh
  472.     adc    al,40h            ;like magic, it's ASCII!
  473.  
  474.     pop    cx
  475.  
  476.     ret
  477.  
  478. byte_to_hex_ascii    endp
  479.  
  480. hex_ascii_to_byte    proc    near
  481. ;converts an ASCII string of two characters in AX to a binary number in AL.
  482. ;Returns carry set if error.
  483.  
  484.     push    dx
  485.     xor    dx,dx
  486.     xchg    ah,al
  487.     push    ax
  488.  
  489.     call    hex_ascii_to_nibble
  490.     pop    ax
  491.     jc    end_hex_ascii_to_byte
  492.  
  493.     push    cx
  494.     mov    cx,4
  495.     shl    dx,cl        
  496.     pop    cx
  497.  
  498.     xchg    ah,al
  499.     call    hex_ascii_to_nibble
  500.     jc    end_hex_ascii_to_byte
  501.  
  502.     mov    ax,dx
  503.  
  504. end_hex_ascii_to_byte:
  505.     pop    dx
  506.  
  507.     ret
  508.  
  509. hex_ascii_to_nibble    proc    near
  510. ;Converts one hex digit in AL to binary and adds it to DX.  Returns carry
  511. ;set if ASCII character in AL is not a valid hex digit.  Accepts upper or
  512. ;lower case letters.
  513.  
  514.     sub    al,30h
  515.     jb    hex_ascii_to_nibble_error
  516.  
  517.     cmp    al,9
  518.     jle    add_it_to_dx
  519.  
  520.     and    al,5fh            ;convert lower case
  521.     sub    al,7
  522.     jb    hex_ascii_to_nibble_error
  523.  
  524.     cmp    al,15
  525.     jg    hex_ascii_to_nibble_error
  526.  
  527. add_it_to_dx:
  528.     cbw
  529.     add    dx,ax
  530.  
  531.     clc
  532.     ret
  533.  
  534. hex_ascii_to_nibble_error:
  535.     stc
  536.     ret
  537.  
  538. hex_ascii_to_nibble    endp
  539.  
  540. hex_ascii_to_byte    endp
  541.  
  542. current_cmd_tail_position    dw    0    ;storage for use by
  543. characters_left_in_cmd_tail    db    0ffh    ;scan_cmd_tail
  544.  
  545. scan_cmd_tail    proc    near
  546. ;procedure to get parameters off the command line.  If no more parameters
  547. ;are present, returns carry set.  If the next parameter is a switch (prefixed by
  548. ;"/" or "-"), the switch is returned in AL (converted to uppercase) and
  549. ;SI will point to the first character after the switch.
  550. ;Otherwise, AL will be zero; SI will point to the beginning of the
  551. ;parameter; and CX will contain the length of the parameter.  In any case,
  552. ;SI, AH and CX are destroyed
  553.  
  554.     push    dx
  555.  
  556.     clc                ;assume more characters in tail
  557.  
  558.     cmp    characters_left_in_cmd_tail,0ffh    ;assuming the command
  559.     jne    not_first_call        ; tail isn't ever really this long
  560.  
  561.     mov    al,cmd_tail_length
  562.     inc    al            ;include <return> in count
  563.     mov    characters_left_in_cmd_tail,al
  564.     mov    ax,offset program:cmd_tail    ;initialize our variables
  565.     mov    current_cmd_tail_position,ax
  566.  
  567.     mov    cl,cmd_tail_length
  568.     xor    ch,ch
  569.     jcxz    no_more_parameters
  570.  
  571.     mov    si,ax            ;set up to capitalize the
  572.     mov    di,ax              ; entire command tail
  573.  
  574. capitalize_cmd_tail_loop:
  575.     lodsb
  576.     cmp    al,'a'
  577.     jb    end_capitalize_loop
  578.     cmp    al,'z'
  579.     ja    end_capitalize_loop
  580.  
  581.     and    al,0dfh            ;convert to uppercase
  582.  
  583. end_capitalize_loop:
  584.     stosb
  585.     loop    capitalize_cmd_tail_loop
  586.  
  587. not_first_call:
  588.     mov    cl,characters_left_in_cmd_tail
  589.     xor    ch,ch
  590.     jcxz    no_more_parameters
  591.  
  592.     mov    si,current_cmd_tail_position
  593.  
  594. scan_tail_loop:
  595.     lodsb                ;get next character
  596.     dec    cx
  597.  
  598.     cmp    al,' '            ;see if it's whitespace
  599.     je    scan_tail_loop
  600.     cmp    al,tab
  601.     je    scan_tail_loop
  602.  
  603.     cmp    al,cr            ;check for end of tail
  604.     je    no_more_parameters
  605.  
  606.     cmp    al,'/'            ;found something, is it a switch?
  607.     je    found_a_switch
  608.     cmp    al,'-'
  609.     je    found_a_switch
  610.  
  611.     call    scan_a_non_switch    ;it's not a switch, scan it
  612.     inc    cx            ;correct character count
  613.  
  614.     xor    al,al            ;flag that a non-switch was found
  615.  
  616.     jmp    short finished_scan_cmd_tail
  617.  
  618. found_a_switch:
  619.     lodsb                ;get the switch
  620.     dec    cx
  621.  
  622.     push    ax            ;save it
  623.  
  624.     call    scan_a_non_switch    ;get any trailing string
  625.  
  626.     pop    ax            ;restore switch
  627.     inc    si            ;make SI point to trailing chars
  628.  
  629.     jmp    short finished_scan_cmd_tail
  630.  
  631. no_more_parameters:
  632.     stc
  633.  
  634. finished_scan_cmd_tail:
  635.     pop    dx
  636.     ret
  637.  
  638. scan_a_non_switch    proc    near
  639. ;scans through a non-switch string or the string following a switch to
  640. ;find the end and the length.
  641.     push    si            ;found a non-switch, save beginning
  642.     push    cx
  643.  
  644. loop_over_nonswitch_chars:
  645.     lodsb                ;get next character
  646.     dec    cx
  647.  
  648.     cmp    al,' '            ;see if it's whitespace
  649.     je    found_end_of_nonswitch
  650.     cmp    al,tab
  651.     je    found_end_of_nonswitch
  652.     cmp    al,'-'            ;or maybe it's the beginning of
  653.     je    found_end_of_nonswitch    ;another switch
  654.     cmp    al,'/'
  655.     je    found_end_of_nonswitch
  656.  
  657.     cmp    al,cr            ;check for end of tail
  658.     jne    loop_over_nonswitch_chars
  659.  
  660. found_end_of_nonswitch:
  661.     dec    si
  662.     mov    current_cmd_tail_position,si    ;save our state for next call
  663.     inc    cl
  664.     mov    characters_left_in_cmd_tail,cl
  665.  
  666.     mov    dx,cx            ;get character count
  667.     pop    cx
  668.     sub    cx,dx
  669.  
  670.     pop    si            ;get pointer to beginning of string    
  671.     dec    si
  672.  
  673.     ret
  674. scan_a_non_switch    endp
  675.  
  676. scan_cmd_tail    endp
  677.  
  678. check_interrupt    proc    near
  679. ;procedure to determine the status of a particular interrupt.  Called with
  680. ;al = interrupt number.  Returns 0 in al if there is no interrupt handler
  681. ;installed, 1 in al if this program is installed, 2 in al if some other
  682. ;program is installed.  In any case, dx will contain the segment to
  683. ;which the vector currently points and bx will contain the offset.
  684. ;AH is destroyed.
  685.  
  686.     push    es
  687.     push    di
  688.     push    si
  689.     push    cx
  690.  
  691.     mov    ah,35h
  692.     int    21h            ;get interrupt vector
  693.     assume es:nothing
  694.  
  695.     mov    cx,es
  696.     mov    dx,cx            ;save segment of vector in dx
  697.     or    cx,bx            ;is the vector 0000:0000?
  698.     jz    no_handler_installed    ;yup, nobody home
  699.  
  700.     mov    al,es:[bx]        ;get the byte to which it points
  701.     cmp    al,iret_instruction
  702.     je    no_handler_installed    ;if it's just an interrupt return
  703.                     ; the handler is a dummy
  704.  
  705. ;OK, someone appears to be installed.  Is it us?
  706.  
  707.     mov     di,bx
  708.                     ;if it's us, es:di now points to the
  709.                     ; beginning of the code
  710.                     ; in the resident version
  711.     mov    si,bx
  712.                     ;and ds:si points to the same code
  713.                     ; in this version
  714.     mov    cx,interrupt_handler_length    ;check all the code
  715.  
  716.     cld
  717.     repe    cmpsb            ;are the two versions equal?
  718.  
  719.     jcxz    we_are_installed    ;yup, it's gotta be us
  720.  
  721.     mov    al,2            ;somebody else is there, signature
  722.     jmp    short end_check_interrupt    ; didn't match
  723.  
  724. no_handler_installed:
  725.     xor    al,al
  726.     jmp    short    end_check_interrupt
  727.  
  728. we_are_installed:
  729.     mov    al,1            ;signature matched, we're installed
  730.  
  731. end_check_interrupt:
  732.     pop    cx
  733.     pop    si
  734.     pop    di
  735.     pop    es
  736.     assume es:program
  737.  
  738.     ret
  739. check_interrupt    endp
  740.  
  741. decimal_ascii_to_word    proc    near
  742. ;converts the ASCII string pointed to by SI to a binary number.  The first
  743. ;non-digit terminates the conversion.  The binary number is returned
  744. ;in DX.  Clears the direction flag.  Returns SI pointing at the first
  745. ;non-digit character.
  746.  
  747.     cld
  748.     push    cx
  749.     push    ax
  750.  
  751.     xor    dx,dx            ;initialize DX
  752.  
  753. dec_ascii_loop:
  754.     lodsb                ;get next digit
  755.     sub    al,30h            ;convert to number
  756.     jl    dec_ascii_done        ;terminate if too small
  757.     cmp    al,9
  758.     jg    dec_ascii_done        ;terminate if too large
  759.     push    ax            ;save digit
  760.     mov    ax,dx
  761.     mov    cx,10
  762.     mul    cx            ;multiply curent number by 10
  763.     mov    dx,ax            ;put it back in DX
  764.     pop    ax            ;get digit back
  765.     add    dx,ax            ;add it to the current number
  766.     jmp    dec_ascii_loop        ;on to the next digit
  767.  
  768. dec_ascii_done:
  769.     dec    si            ;point SI at character that stopped us
  770.     pop    ax
  771.     pop    cx
  772.  
  773.     ret
  774.  
  775. decimal_ascii_to_word    endp
  776.  
  777. transient_code    ends
  778.  
  779. ;************************ RESIDENT INTERRUPT HANDLER CODE ***************
  780.  
  781.  
  782.     org    2ch
  783. env_segment    dw    ?        ;segment address of our environment
  784.  
  785.     org 80h
  786. cmd_tail_length    db    ?        ;length of our command line tail
  787. cmd_tail    db    ?        ;contents of our command line tail
  788.  
  789. ;Now we can actually start the main (resident) code
  790.     org    100h
  791.     assume cs:program,ds:program,es:program,ss:program
  792.  
  793. start:
  794.     jmp    start_transient_code    ;enter here only on initial
  795.                     ;(installation) call
  796.  
  797. interrupt_handler:            ;entry point for interrupt
  798.                     ; handling routine
  799.  
  800.     assume cs:program,ds:nothing,es:nothing,ss:nothing
  801.  
  802.     sti                ;resume the maddening buzz of
  803.                     ; interrupts
  804.  
  805.                     ;we'll assume the caller has a big
  806.                     ; enough stack, since we don't use
  807.                     ; much
  808.     push    ds            ;we'll need to restore DS later
  809.     push    ax            ;we may need to restore AX later
  810.                     ; in case of a TERMINATE
  811.     push    dx
  812.     push    bx
  813.     push    cx
  814.  
  815.     push    cs            ;establish proper data segment
  816.     pop    ds
  817.     assume ds:program
  818.                     ;select proper section of code to
  819.                     ;execute
  820.     dec    ax
  821.     dec    ax
  822.     jz    terminate        ;AX was equal to 2
  823.     js    initialize        ;AX was equal to 1 (or less)
  824.  
  825.                     ;AX was equal to 3 (or more)
  826.  
  827. ;********************** SECTION TO SENSE THE MOUSE STATE **********
  828.  
  829. sense_state:
  830.     mov    ax,read_pos_and_buttons
  831.     int    33h            ;ask the mouse what buttons are
  832.                      ; pressed
  833.     or    bx,bx
  834.     jz    no_buttons_pressed
  835.  
  836.     or    save_button_status,bl    ;some button is pressed, save all
  837.                                 ; button presses until they're all
  838.                     ; released.  We'll ignore mouse
  839.                     ; motions until all buttons are
  840.                     ; released
  841.         pop     cx                      ;restore CX, BX
  842.         pop     bx
  843.  
  844.         xor     ax,ax                   ;return "nothing"
  845.  
  846. return_with_dx_popped:
  847.     pop    dx            ;restore DX
  848.     inc    sp            ;discard pushed AX
  849.     inc    sp
  850.     pop    ds            ;restore DS
  851.     assume ds:nothing
  852.     iret
  853.     assume ds:program
  854.  
  855.  
  856. no_buttons_pressed:
  857.     mov    al,save_button_status    ;no button is pressed; were any
  858.     or    al,al            ; buttons pressed previously?
  859.     jnz    check_for_pick        ;yup
  860.  
  861.                         ;no buttons are or have been pressed
  862.     call    get_position        ;update current mouse position
  863.     mov    ax,2            ;return "tracking"
  864.  
  865.     jmp    short return_coords
  866.  
  867. check_for_pick:                ;at least one button has been
  868.                            ; pressed.  check for special "pick"
  869.     dec    al            ; button
  870.     jnz    return_button_and_coords
  871.                     ;left (pick) button was pressed
  872.     mov    save_button_status,al    ;reset button status to zero
  873.  
  874.                     ;don't update coordinates so what
  875.                     ; counts is where the cursor was
  876.                     ; when the user PRESSED the pick
  877.                     ; button
  878.     mov    ax,3            ;return "picked point"
  879.  
  880. return_coords:
  881.     add    sp,4            ;discard pushed CX, BX
  882.     mov    bx,x_coord
  883.     mov    cx,y_coord
  884.     jmp    return_with_dx_popped
  885.  
  886. return_button_and_coords:        ;some button(s) other than just the
  887.                      ; left have been pressed
  888.  
  889.                     ;translate to AutoCAD button number.
  890.                     ; note that save_button_status - 1
  891.                     ; is in AL, minimum value = 1,
  892.                     ; maximum value = 6
  893.     mov    bx,offset program:button_translate_table-1
  894.     xlat
  895.     cbw
  896.     mov    bx,ax            ;BX = AutoCAD button number
  897.  
  898.     mov    save_button_status,ah    ;reset button status
  899.  
  900.     call    get_position        ;update current mouse position
  901.  
  902.     mov    cx,x_coord
  903.     mov    dx,y_coord
  904.     mov    ax,5            ;return "button and coordinates"
  905.     add    sp,8            ;discard pushed CX, BX, DX, AX
  906.     pop    ds            ;restore DS
  907.     assume ds:nothing
  908.     iret
  909.     assume ds:program
  910.  
  911. ;************************* SECTION TO TERMINATE *********************
  912.  
  913. terminate:
  914.     add    sp,6            ;discard pushed DX, CX, BX
  915.     pop    ax            ;restore AX
  916.     pop    ds            ;restore DS
  917.     assume ds:nothing
  918.     iret
  919.     assume ds:program
  920.     
  921. ;************************ SECTION TO INITIALIZE *********************
  922.  
  923. initialize:
  924.  
  925.     cmp    bx,interface_level
  926.     jne    init_error_exit        ;unknown interface level code
  927.  
  928.     xor    ax,ax            ;check to see if mouse driver is
  929.     int 33h                ; present (and zero motion counters)
  930.  
  931.     cmp    ax,mouse_driver_installed
  932.     jz    how_many_buttons
  933.                      ;no mouse driver installed
  934. init_error_exit:
  935.     xor    ax,ax            ;failed init code
  936.  
  937.     pop    cx            ;restore CX and BX
  938.     pop    bx
  939.  
  940.     jmp    short init_exit
  941.  
  942. how_many_buttons:
  943.     cmp    bx,3            ;three button mouse?
  944.     jz    init_ok            ;yup
  945.  
  946.     mov    button_translate_table,0    ;nope, two buttons; need to
  947.     mov    button_translate_table+1,1    ; change translate table so
  948.                         ; right button is button 0
  949.                         ; and left+right buttons is
  950.                         ; button 1
  951.  
  952. init_ok:
  953.     xor    ax,ax            ;initialize coordinates and
  954.     mov    save_button_status,al    ; button status
  955.     mov    x_coord,ax
  956.     mov    y_coord,ax
  957.                          ;set up return values
  958.     xor    bx,bx            ;relative pointing device
  959.     xor    cx,cx            ;continuous samples
  960.     inc    ax            ;init OK code = 1
  961.  
  962.     pop    dx            ;discard pushed CX, BX
  963.     pop    dx
  964.  
  965. init_exit:
  966.     pop    dx            ;restore DX
  967.     inc    sp            ;discard pushed AX
  968.     inc    sp
  969.     pop    ds
  970.     assume ds:nothing
  971.     iret
  972.     assume ds:program
  973.  
  974. ;*************************** RESIDENT SUPPORT ROUTINES **************
  975.  
  976. get_position    proc    near
  977. ;procedure to get the increment of mouse motions since the last call
  978. ;and update the "absolute" X and Y coordinates.  Destroys AX, BX, CX, DX.
  979.  
  980.     mov    ax,read_counters_function
  981.     int    33h            ;ask the mouse where it's moved to
  982.  
  983.     mov    ax,dx            ;y motion in mickeys
  984.     neg    ax            ;AutoCAD & mouse use opposite signs
  985.     imul    motion_scale_factor    ;scale it up (32 bit result)
  986.     add    ax,y_coord        ;add current position (32 bit
  987.     adc    dx,0            ; addition, but we know the top
  988.                     ; 16 bits of current position are 0)
  989.     js    set_y_to_zero        ;if result negative, clip to min
  990.     jnz    set_y_to_max        ;if DX positive but nonzero, clip to
  991.                     ; max
  992.     cmp    ax,20480d
  993.     jna    save_y            ;if AX isn't too big, just save
  994.  
  995. set_y_to_max:
  996.     mov    ax,20480d        ;maximum value of y coordinate
  997.     jmp    short save_y
  998.  
  999. set_y_to_zero:
  1000.     xor    ax,ax            ;0 = minimum value of y coordinate
  1001.  
  1002. save_y:
  1003.     mov    y_coord,ax
  1004.  
  1005.     mov    ax,cx            ;x motion in mickeys
  1006.     imul    motion_scale_factor    ;scale it up (32 bit result)
  1007.     add    ax,x_coord        ;add current position (32 bit
  1008.     adc    dx,0            ; addition, but we know the top
  1009.                     ; 16 bits of current position are 0)
  1010.     js    set_x_to_zero        ;if result negative, clip to min
  1011.     jnz    set_x_to_max        ;if DX positive but nonzero, clip to
  1012.                     ; max
  1013.     cmp    ax,20480d
  1014.     jna    save_x            ;if AX isn't too big, just save it
  1015.  
  1016. set_x_to_max:
  1017.     mov    ax,20480d        ;maximum value of x coordinate
  1018.     jmp    short save_x
  1019.  
  1020. set_x_to_zero:
  1021.     xor    ax,ax            ;0 = minimum value of x coordinate
  1022.  
  1023. save_x:
  1024.     mov    x_coord,ax        ;save x coordinate
  1025.     ret
  1026.  
  1027. interrupt_handler_length    equ    $ - interrupt_handler
  1028.  
  1029. get_position    endp
  1030.  
  1031. main_code    ends
  1032.         end    start
  1033.